/*
 * casper-lock.c
 *
 *  Created on: 11/mar/2011
 *      Author: ivano
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <memory.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <sys/errno.h>

#include "../terminals.h"

terminal_t* term;

int main (int argc, char *argv[]) {
	int sock, i;
	struct sockaddr_un my_addr;
	char buffer[255], *response, *ptr;
	int state = 0, reqid;
	// Parametri
	char *sock_name = NULL, *category = NULL, *node = NULL;
	int job_id = -1;

	for (i = 1; i < argc; i++) {
		if (!strcmp(argv[i], "-s")) {
			sock_name = argv[++i];
		}
		else if (!strcmp(argv[i], "-c")) {
			category = argv[++i];
		}
		else if (!strcmp(argv[i], "-u")) {
			node = argv[++i];
		}
		else if (!strcmp(argv[i], "-j")) {
			if (sscanf(argv[++i], "%d", &job_id) != 1)
				fprintf(stderr, "WARNING: casper-lock: invalid job id \"%s\"\n", argv[i]);
		}
		else {
			fprintf(stderr, "ERROR: casper-lock: unrecognized parameter \"%s\"\n", argv[i]);
			exit(1);
		}
	}

	if (sock_name == NULL || sock_name[0] == '-') {
		sock_name = getenv("CASPER_BUSCONSOLE_SOCKET");
		if (sock_name == NULL) {
			fprintf(stderr, "ERROR: casper-lock: unspecified socket\n");
			return 1;
		}
	}
	if ((category == NULL || category[0] == '-') && (node == NULL || node[0] == '-')) {
		fprintf(stderr, "ERROR: casper-lock: unspecified category to lock or node to unlock\n");
		return 1;
	}
	if (job_id == -1) {
		ptr = getenv("JOB_ID");
		if (ptr == NULL)
			fprintf(stderr, "WARNING: casper-lock: JOB_ID variable not available\n");
		else if (sscanf(ptr, "%d", &job_id) != 1)
			fprintf(stderr, "WARNING: casper-lock: unable to read job id from JOB_ID variable (value: %s)\n", ptr);
	}

	//setvbuf(stdout,NULL,_IONBF,0);

	sock = socket(AF_UNIX, SOCK_STREAM, 0);
	if (sock == -1) {
		fprintf(stderr, "ERROR: casper-lock: socket() failed: unable to create local UNIX socket (errno: %d)\n", errno);
		return errno;
	}

	memset(&my_addr, 0, sizeof(struct sockaddr_un));

	my_addr.sun_family = AF_UNIX;
	strncpy(my_addr.sun_path, sock_name, sizeof(my_addr.sun_path) - 1);

	//connect(sockfd,(struct sockaddr *) &serv_addr,sizeof(serv_addr))
	if (connect(sock, (struct sockaddr *) &my_addr, sizeof(struct sockaddr_un)) == -1) {
		fprintf(stderr, "ERROR: casper-lock: connect() failed: unable to connect to local UNIX socket %s (errno: %d)\n", sock_name, errno);
		fprintf(stderr, "ERROR: -> %s\n", strerror(errno));
		return errno;
	}

	// Starting terminal
	term = terminal_new_socket(sock);

	if (node && node[0] != '-') {
		sprintf(buffer, "locks unlock %s", node);
		terminal_write_to_daemon(term, buffer);
	}
	if (category && category[0] != '-') {
		sprintf(buffer, "transaction locks request %d %s", job_id, category);
		terminal_write_to_daemon(term, buffer);

		while (1) {
			response = terminal_read_from_daemon(term);
			if (response == NULL) {
				fprintf(stderr, "ERROR: casper-lock: connection closed from daemon\n");
				exit(1);
			}
			if (!strncmp(response, "jobs ", 5)) {
				ptr = &response[5];
				if (sscanf(ptr, "%d", &i) == 1 && i == job_id) {
					sscanf(ptr, "%s", buffer);
					ptr += strlen(buffer);
					if (ptr[0] == ' ' && !strncmp(&ptr[1], "finished ", 9))
						// Job finished (or aborted or killed or error occurred), lock not needed
						exit(1);
				}
			}
			switch (state) {
				case 0:
					if (!strcmp(response, "transaction begin"))
						state = 1;
					break;
				case 1:
					if (!strncmp(response, "locks request ", 14)) {
						ptr = &response[14];
						sscanf(ptr, "%d", &reqid);
						state = 2;
					}
					else if (!strcmp(response, "transaction end")) {
						fprintf(stderr, "ERROR: casper-lock: category \"%s\" not found\n", category);
						exit(1);
					}
					break;
				case 2:
					if (!strcmp(response, "transaction end"))
						state = 3;
					break;
				case 3:
					if (!strncmp(response, "unlocked ", 9)) {
						ptr = &response[9];
						sscanf(ptr, "%d", &i);
						sscanf(ptr, "%s", buffer);
						ptr += strlen(buffer) + 1;
						if (i == reqid) {
							printf("%s", ptr);
							return 0;
						}
					}
					break;
			}
			free(response);
		}
	}
}
